﻿using System;
using System.Collections.Generic;

namespace CSharpConsoleTestSolution.Demo {
    //P17: 字段, 属性, 索引器, 常量
    public class P17_Field_Attribute_Indexer_Const {
        /**
         * 字段修饰符, 时间: 18:40
         *
         * new
         * public
         * private
         * protected
         * static
         * 
         * internal
         * readonly
         * volatile
         */
        /**
         * 静态构造器, 时间: 24:56
         */
        public static void static_Constructor() {
            Student student = new Student(); //"静态构造器!"      and     "普通构造器!"
            student.Age = 30;
            Console.WriteLine($"Age = {student.Age}, Amount = {Student.Amount}"); //Age = 30, Amount = 5
            student = null;

            Student.Amount = 10;
            Student student2 = new Student(); //"普通构造器!"
            Console.WriteLine($"Age = {student2.Age}, Amount = {Student.Amount}"); //Age = 20, Amount = 10
        }

        private class Student {
            public int Age = 20;
            public static int Amount;
            public readonly int ID;

            static Student() { //1.静态构造器, 只会初始化1次
                Amount = 5;
                Console.WriteLine("1.静态构造器!"); //只会打印1次
            }

            public Student() {
                Console.WriteLine("2.普通构造器!"); //每次都会打印
            }
        }


        /**
         * readonly(相当于java的final) 只读, 只有1次赋值机会, 时间: 26:50
         */
        public static void readonly_test() {
            Console.WriteLine("\n\n");
            Student2 student = new Student2(27);
            // student.ID = 5;              //报错
            // Student2.DefaultColor.R = 5; //报错
            
            // Student2.DefaultColor2 = ConsoleColor.Blue;  //报错
        }

        private class Student2 {
            public readonly int ID; //readonly
            
            //TODO: WPF的包吗? 没找到这个类, 另外找一个!
            // public static readonly System.Windows.Media.Color
            //     DefaultColor = new System.Windows.Media.Color(); //readonly 的静态只读字段

            private static readonly ConsoleColor DefaultColor2 = ConsoleColor.Red;

            static Student2() {
                //静态只读字段, 也可以在 静态构造函数中初始化
                // DefaultColor = new System.Windows.Media.Color();
                
                DefaultColor2 = ConsoleColor.Green;
            }

            public Student2(int id) {
                this.ID = id;
            }
        }


        /**
         * 字段的属性, 时间: 46:15
         */
        public static void field_property() {
            Console.WriteLine("\n\n");
            Student3 student = new Student3();
            // student.setAge(120);

            student.Age = 140;

            Console.WriteLine("调用完成!");
        }

        private class Student3 {
            private int age;

            public int Age {
                get {
                    // return Age;              //这样不行, 会递归调用
                    return age;
                }

                set {
                    if (value >= 0 && value < 150) {
                        // Age = value;         //这样不行, 会递归调用
                        age = value;
                    }
                    else throw new Exception("Age value has error!");
                }
            }

            // public int getAge() {
            //     return Age;
            // }
            // public void setAge(int age) {
            //     if (age >= 0 && age < 150) {
            //         this.Age = age;
            //     } else throw new Exception("Age value has error!");
            // }
        }


        /**
         * 字段属性 的 简略声明, 时间: 54:55
         */
        public static void field_property_simple_announcement() {
            Console.WriteLine("\n\n");
            Student4 student = new Student4();

            student.Age = 130;
            student.ID = 27;

            Console.WriteLine($"student.Age = {student.Age}, student.ID = {student.ID}");
        }

        private class Student4 {
            private int age;

            public int ID { get; set; }

            public int Age {
                get { return age; }
                set { age = value; }
            }
        }


        /**
         * 字段只读, 时间: 1:03:02
         */
        public static void field_getter_only() {
            Console.WriteLine("\n\n");
            Student5 student = new Student5();
            int age = student.Age; //age只读

            // student.ID = 5;      //ID 的 set 是private, 不能这样赋值

            Console.WriteLine($"student.Age = {student.Age}, student.ID = {student.ID}");

            student.SomeMethod(); //Student 里面的方法才能赋值
            Console.WriteLine($"student.Age = {student.Age}, student.ID = {student.ID}");

            Console.WriteLine($"动态计算的字段: student.CanWork = {student.CanWork}");
        }

        private class Student5 {
            private int age = 25;
            private int id = 27;

            public int ID {
                get { return id; }
                private set { this.id = value; } //private, 只有类里面可以设置, 外部不可以设置
            }

            public int Age {
                get { return age; }
                // set { age = value; }             //age 没有 set 方法
            }

            public bool CanWork { //动态计算的字段
                get { return Age >= 16; }
            }

            public void SomeMethod() {
                this.ID = 28; //private, 只有类里面可以设置, 外部不可以设置
            }
        }


        /**
         * 自定义 索引器(indexer + Enter), 时间: 1:16:50
         */
        public static void indexer_exam() {
            Console.WriteLine("\n\n");
            Student6 student = new Student6();
            student["Math"] = 120;
            student["Chinese"] = 90;
            
            Console.WriteLine($"student.Math = {student["Math"].Value}, student.Chemistry = {student["Chemistry"]}");

            student["Math"] = 135;
            student["Chemistry"] = 115;
            Console.WriteLine($"student.Math = {student["Math"]}, student.Chemistry = {student["Chemistry"]}");
        }
        private class Student6 {
            private readonly IDictionary<string, int> _scoreDictionary = new Dictionary<string, int>();

            /**
             * 输入 indexer + Enter, 自动生成
             * int?     : 返回值类型
             * string   : 索引类型
             * this     : 本对象
             */
            public int? this[string index] {
                get {
                    if (_scoreDictionary.ContainsKey(index)) {
                        return _scoreDictionary[index];      //要先判断是否有这个值, 否则报错: System.ThrowHelper.ThrowKeyNotFoundException()
                    } 
                    return null;
                }
                set {
                    //value 是 int? 类型
                    if (value.HasValue) {
                        if (_scoreDictionary.ContainsKey(index)) {
                            _scoreDictionary[index] = value.Value;
                        } else _scoreDictionary.Add(index, value.Value);
                    } else throw new Exception("Score can't be null!");
                }
            }
        }


        private static readonly Student6 student6 = new Student6();    //正确
        /**
         * 常量 const
         */
        public static void const_exam() {
            Console.WriteLine("\n");
            //public const double PI = 3.141592653589793;
            double pi = Math.PI;
            int maxValue = int.MaxValue;
            Console.WriteLine($"PI = {Math.PI}");
            
            // const Student6 student6 = new Student6();    //报错
            Console.WriteLine($"const Student6 student6 = new Student6();    //报错, 常量隶属于'类型'不是'对象', 即没有\"实例常量\"");
            Console.WriteLine($"public static readonly Student6 student6 = new Student6();    //正确");
        }
    }
}